package com.shiftychess.model
{
	import com.shiftychess.board.Colour;
	import com.shiftychess.board.Position;
	import com.shiftychess.piece.Bishop;
	import com.shiftychess.piece.IChessPiece;
	import com.shiftychess.piece.King;
	import com.shiftychess.piece.Knight;
	import com.shiftychess.piece.Pawn;
	import com.shiftychess.piece.Queen;
	import com.shiftychess.piece.Rook;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	
	public class GameModel
	{	
		private static var _pieces:Array;
					
		public function GameModel() {			
		}
		
		public static function set pieces(values:Array):void {
			_pieces = values;
		}	
			
		public static function get pieces():Array {
			return _pieces;
		}
		
		private static function getPiece(pieceId:int):IChessPiece {
			for(var i:int; i < _pieces.length; i++) {
				if(pieceId == _pieces[i].pieceId) {
					switch(_pieces[i].type) {
						case "bishop":
							return _pieces[i] as Bishop;
						case "king":
							return _pieces[i] as King;
						case "knight":
							return _pieces[i] as Knight;
						case "pawn":
							return _pieces[i] as Pawn;
						case "queen":
							return _pieces[i] as Queen;
						case "rook":
							return _pieces[i] as Rook;
						default:
							return null;
					}
				}
			}
			
			return null;
		}
		
		public static function getAvailableMoves(pieceId:int):Array {
			var piece:IChessPiece = getPiece(pieceId);
			
			var availableMoves:Array = new Array();
			
			var allPositions:Array = Position.getAllPositions();
			for(var i:int; i < allPositions.length; i++) {
				if(piece.canMove(allPositions[i])) {
					availableMoves.push(allPositions[i]);
				}
			}
			
			return availableMoves;
		}
		
		public static function movePiece(pieceId:int, position:Position):void {
			var piece:IChessPiece = getPiece(pieceId);
			
			var move:Move = new Move();
			move.from = piece.position.x + piece.position.y;
			move.to = position.x + position.y;
			
			for(var i:int; i < _pieces.length; i++) {
				if((_pieces[i] as IChessPiece).position.x == position.x && 
				   (_pieces[i] as IChessPiece).position.y == position.y) {
					move.capture = _pieces[i].type;
					break;
				}
			}
			
			//update piece
			piece.move(position);
						
			//send data to server
			ConnectionManager.getInstance().sendMove(move);
		}
		
		public static function checkEmptySpace(position:Position):Boolean {
			var found:Boolean = false;
			for(var i:int; i < _pieces.length; i++) {
				if(_pieces[i].positionX == position.x && _pieces[i].positionY == position.y) {
					found = true;
					break;
				}
			}
			
			return !found;
		}
		
		public static function checkEnemySpace(position:Position, colour:String):Boolean {
			var enemy:Boolean = false;
			for(var i:int; i < _pieces.length; i++) {
				if(_pieces[i].positionX == position.x && _pieces[i].positionY == position.y) {
					enemy = (colour != _pieces[i].colour);
					break;
				}
			}
			
			return enemy;
		}
		
		public static function checkEmptySpaceBetween(startPosition:Position, endPosition:Position):Boolean {
			var difX:int = Position.convertXtoInt(startPosition.x) - Position.convertXtoInt(endPosition.x);
			var difY:int = startPosition.y - endPosition.y;
			
			var i:int;
			var pos:Position;
			
			if(difX == 0) {
				if(difY > 1) {
					for(i = 1; i < difY; i++) {
						pos = new Position();
						pos.x = startPosition.x;
						pos.y = startPosition.y - i;
						if(!checkEmptySpace(pos)) {
							return false;
						}
					}
				} else {
					for(i = 1; i < Math.abs(difY); i++) {
						pos = new Position();
						pos.x = startPosition.x;
						pos.y = startPosition.y + i;
						if(!checkEmptySpace(pos)) {
							return false;
						}
					}
				}
			} else if(difY == 0) {
				if(difX > 1) {
					for(i = 1; i < difX; i++) {
						pos = new Position();
						pos.x = Position.convertIntToX(Position.convertXtoInt(startPosition.x) - i);
						pos.y = startPosition.y;
						if(!checkEmptySpace(pos)) {
							return false;
						}
					}
				} else {
					for(i = 1; i < Math.abs(difX); i++) {
						pos = new Position();
						pos.x = Position.convertIntToX(Position.convertXtoInt(startPosition.x) + i);
						pos.y = startPosition.y;
						if(!checkEmptySpace(pos)) {
							return false;
						}
					}
				}
			} else {
				for(i = 0; i < Math.abs(difX); i++) {
					pos = new Position();
					if(difX > 0) {
						pos.x = Position.convertIntToX(Position.convertXtoInt(startPosition.x) - i);	
					} else {
						pos.x = Position.convertIntToX(Position.convertXtoInt(startPosition.x) + i);
					}
					if(difY > 0) {
						pos.y = startPosition.y - i;	
					} else {
						pos.y = startPosition.y + i;
					}
					if(!checkEmptySpace(pos)) {
						return false;
					}
				}
			}
			
			return true;
		}
		
		public static function isCheck(position:Position, colour:String):Boolean {
			var check:Boolean = false;
			for(var i:int; i < _pieces.length; i++) {
				if(colour != _pieces[i].colour) {
					if((_pieces[i] as IChessPiece).canMove(position)) {
						check = true;
						break;
					}	
				}
			}
			
			return check;
		}
		
		public static function isCheckMate():void {
			//get the king of both colours.
			//is the king checked?
			//can he still move?

			var i:int;
			var j:int;
			var pos:Position;
			var kingX:int
			var kingY:int
			var tstX:int
			var tstY:int
						
			//check WHITE
			
			//get king
			var king:IChessPiece;
			for(i = 0; i < _pieces.length; i++) {
				if(_pieces[i].colour == Colour.WHITE && _pieces[i].type == "king") {
					king = _pieces[i] as IChessPiece; 
				}
			}
			
			var checker:IChessPiece = canBeTakenBy(king.position, Colour.WHITE);
			
			if(checker != null) {
				//can the piece that checks the king, be taken?
				if(canBeTakenBy(checker.position, Colour.BLACK) == null) {
					kingX = Position.convertXtoInt(king.position.x);
					kingY = king.position.y;
					//can he still move?
					for(i = -1; i < 2; i++) {
						for(j = -1; j < 2; j++) {
							if(!(i == 0 && j == 0)) {
								tstX = kingX + i;
								tstY = kingY + j;
								if(tstX > 0 && tstX < 9 && tstY > 0 && tstY < 9) {
									pos = new Position();
									pos.x = Position.convertIntToX(tstX);
									pos.y = tstY;
									if(!isCheck(pos, Colour.WHITE)) {
										return;
									}
								}
							} 
						}
					}
					
					//checkmate for WHITE
					ConnectionManager.getInstance().endGame(Colour.BLACK);
					return;
				}
			}
			
			//check BLACK
			
			//get king
			for(i = 0; i < _pieces.length; i++) {
				if(_pieces[i].colour == Colour.BLACK && _pieces[i].type == "king") {
					king = _pieces[i] as IChessPiece; 
				}
			}
			
			checker = canBeTakenBy(king.position, Colour.BLACK);
			
			if(checker != null) {
				//can the piece that checks the king, be taken?
				if(canBeTakenBy(checker.position, Colour.WHITE) == null) {
					kingX = Position.convertXtoInt(king.position.x);
					kingY = king.position.y;
					//can he still move?
					for(i = -1; i < 2; i++) {
						for(j = -1; j < 2; j++) {
							if(!(i == 0 && j == 0)) {
								tstX = kingX + i;
								tstY = kingY + j;
								if(tstX > 0 && tstX < 9 && tstY > 0 && tstY < 9) {
									pos = new Position();
									pos.x = Position.convertIntToX(tstX);
									pos.y = tstY;
									if(!isCheck(pos, Colour.BLACK)) {
										return;
									}
								}
							} 
						}
					}
					
					//checkmate for BLACK
					ConnectionManager.getInstance().endGame(Colour.WHITE);
					return;
				}
			}
		}
		
		private static function canBeTakenBy(position:Position, colour:String):IChessPiece {
			for(var i:int; i < _pieces.length; i++) {
				if(colour != _pieces[i].colour) {
					if((_pieces[i] as IChessPiece).canMove(position)) {
						return _pieces[i] as IChessPiece;
					}	
				}
			}
			return null;
		}
	}
}